package com.dhcc.bpm.modules.system.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dhcc.bpm.common.annotation.Log;
import com.dhcc.bpm.common.enums.BusinessType;
import com.dhcc.bpm.common.utils.CreateInsert;
import com.dhcc.bpm.common.utils.FilEUploadUtils;
import com.dhcc.bpm.common.utils.FileUtils;
import com.dhcc.bpm.common.utils.StringUtils;
import com.dhcc.bpm.modules.api.service.IApiService;
import com.dhcc.bpm.modules.api.service.IBaseProductService;
import com.dhcc.bpm.modules.api.service.ISysService;
import com.dhcc.bpm.modules.system.entity.ExpSeq;
import com.dhcc.bpm.modules.system.entity.ExpSeqEntity;
import com.dhcc.bpm.modules.system.service.IExpSeqService;
import com.dhcc.bpm.modules.system.service.ISerialNumberService;
import com.dhcc.bpm.modules.system.service.impl.FactoryForServiceStrategy;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.poi.ss.formula.functions.T;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @version V1.0
 * @ClassName TestController
 * @Description TODO
 * @Author xiafayu
 * @Date 2020/12/23 10:49
 * @Copyright: 2020 东华软件 .. All rights reserved.
 */
@RestController
@AllArgsConstructor
@NoArgsConstructor
@Api(value = "导出数据", tags = "导出数据")
@RequestMapping(AppConstant.APPLICATION_SYSTEM_NAME + "/expSeq")
public class ExpSeqController {
    private static final Logger log = LoggerFactory.getLogger(ExpSeqController.class);
    @Autowired
    CreateInsert createInsert;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ISerialNumberService serialNumberService;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private IExpSeqService expSeqService;
    @Autowired
    private FactoryForServiceStrategy factoryForStrategy;
    private static final String EXP_SQE = "expSeq";

    @Autowired
    private ISysService sysService;

    @Autowired
    private IBaseProductService baseProductService;

    @Value("${bpm.expTableList}")
    private String expTableLis;

    @Autowired
    private IApiService apiService;

    @Value("${bpm.file-public-path}")
    private String baseFilePath;
    /**
     * 获取导出数据标识
     */
    private static String DATA_BY_EXP_SEQ = "select max_serial from opc_serial_number where module_code = 'exp_seq'";

    /*
     * @Description 查询数据库需要导出的表名及数据条数
     * @Author xiafayu
     * @Date 2020/12/24 14:59
     * @return JSONObject
     * @throws
     **/
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "查询导出表详情", notes = "")
    @ApiLog("查询导出表详情")
    @Log(title = "查询导出表详情", businessType = BusinessType.SELECT)
    @GetMapping("/queryTableInfo")
    public R queryTableInfo(Query query, String expSeq) {
        if (StringUtils.isBlank(expSeq)) {
            expSeq = stringRedisTemplate.opsForValue().get(EXP_SQE);
        }
//        IPage<ExpSeqEntity> list = expSeqService.getTableName(Condition.getPage(query));
        String finalExpSeq = expSeq;
//        list.getRecords().forEach(expSeqEntity -> {
//            expSeqEntity.setExpSeq(finalExpSeq);
//            expSeqEntity.setNum(createInsert.queryDataByName(expSeqEntity.getTableEname(), finalExpSeq));
//        });

        IPage<ExpSeqEntity> page = Condition.getPage(query);
        List<String> list = Arrays.asList(expTableLis.split(","));

        page.setTotal(list.size());
        Integer size = query.getSize() == null ? 10 : query.getSize();
        int start = (query.getCurrent() - 1) * size;
        int end = list.size();
        if ((start + size) < list.size()) {
            end = start + size;
        }
        List<ExpSeqEntity> expList = new ArrayList<>();
        for (int i = start; i < end; i++) {
            ExpSeqEntity expSeqEntity = new ExpSeqEntity();
            expSeqEntity.setTableEname(list.get(i).split("-")[0]);
            expSeqEntity.setTableName(list.get(i).split("-")[1]);
            expSeqEntity.setExpSeq(finalExpSeq);
            expSeqEntity.setNum(createInsert.queryDataByName(expSeqEntity.getTableEname(), finalExpSeq));
            expList.add(expSeqEntity);
        }
        page.setRecords(expList);
        return R.data(page);
    }

    /*
     * @Description 导出所有表的数据
     * @Author xiafayu
     * @Date 2020/12/24 15:01
     * @return String
     * @throws  ParseException
     **/
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "生成全部INSERT SQL", notes = "")
    @ApiLog("生成全部INSERT SQL")
    @Log(title = "生成全部INSERT SQL", businessType = BusinessType.OTHER)
    @GetMapping("/createAllTableInsert")
    public R createAllTableInsert(String expSeq) throws ParseException {
        if (StringUtils.isBlank(expSeq)) {
            expSeq = stringRedisTemplate.opsForValue().get(EXP_SQE);
        }
        StringBuilder result = new StringBuilder();
//       List<String> tabList = createInsert.getTableNameByExpSeq();
        List<String> tabList = new ArrayList<>();
        List<String> list = Arrays.asList(expTableLis.split(","));
        list.forEach(str -> {
            tabList.add(str.split("-")[0]);
        });
        for (String tab : tabList) {
            if (tab.indexOf("copy") > 1) {
                continue;
            }

            try {
                result.append(createInsert.getInsertSql(tab, expSeq));
                result.append("\r\n");
            } catch (Exception e) {
                log.error("生成INSERT SQL失败：{}", e);
                return R.fail("生成INSERT SQL失败");
            }
        }
        return R.data(result.toString());
    }


    /*
     * @Description 导出单表的数据
     * @Author xiafayu
     * @Date 2020/12/24 15:01
     * @param  tableName  表名
     * @return String
     * @throws  ParseException
     **/
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "生成INSERT SQL", notes = "传入tableName")
    @ApiLog("生成INSERT SQL")
    @Log(title = "生成INSERT SQL", businessType = BusinessType.OTHER)
    @GetMapping("/createTableInsertByTableName")
    public R createTableInsertByTableName(String tableName, String expSeq) {
        if (StringUtils.isBlank(expSeq)) {
            expSeq = stringRedisTemplate.opsForValue().get(EXP_SQE);
        }
        try {
            String result = createInsert.getInsertSql(tableName, expSeq);
            return R.data(result);
        } catch (Exception e) {
            log.error("生成INSERT SQL失败：{}", e);
            return R.fail("生成INSERT SQL失败");
        }
    }

    @ApiOperationSupport(order = 8)
    @ApiOperation(value = "根据表名和导出标识查询列表", notes = "传入tableName")
    @ApiLog("根据表名和导出标识查询列表")
    @Log(title = "根据表名和导出标识查询列表", businessType = BusinessType.OTHER)
    @GetMapping("/queryListByTableName")
    public R queryListByTableName(String tableName, String expSeq, Query query) throws Exception {
        if (StringUtils.isBlank(expSeq)) {
            expSeq = stringRedisTemplate.opsForValue().get(EXP_SQE);
        }

        IPage<T> result = factoryForStrategy.getStrategy(tableName, query, expSeq);
        return R.data(result);
    }

    /*
     * @Description 导出单表的数据
     * @Author xiafayu
     * @Date 2020/12/24 15:01
     * @param  tableName  表名
     * @return String
     * @throws  ParseException
     **/
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "生成INSERT SQL", notes = "传入tableName")
    @ApiLog("生成INSERT SQL")
    @Log(title = "生成INSERT SQL", businessType = BusinessType.OTHER)
    @PostMapping("/createTableInsertByList")
    public R createTableInsertByList(@ApiParam(value = "表名集合", required = true) @RequestParam("tableNames") String tableNames, String expSeq) {
        List<String> list = null;
        if (StringUtils.isBlank(expSeq)) {
            expSeq = stringRedisTemplate.opsForValue().get(EXP_SQE);
        }
        if (StringUtils.isEmpty(tableNames)) {
            List<String> tabList = new ArrayList<>();
            List<String> lists = Arrays.asList(expTableLis.split(","));
            lists.forEach(str -> {
                tabList.add(str.split("-")[0]);
            });
            list = tabList;
        } else {
            list = Arrays.asList(tableNames.split(","));
        }
        StringBuilder result = new StringBuilder();
        for (String tab : list) {
            if (tab.indexOf("copy") > 1) {
                continue;
            }
            try {
                String sql = createInsert.getInsertSql(tab, expSeq);
                if (!"".equals(sql)) {
                    result.append(sql);
                    result.append("\r\n");
                }
            } catch (Exception e) {
                log.error("生成INSERT SQL失败：{}", e);
                return R.fail("生成INSERT SQL失败");
            }
        }
        return R.data(result.toString());
    }


    /**
     * @param FileName 文件名
     * @Description 下载相关文件压缩包
     * @Author lizeyu
     * @Date 2021年7月26日 14:30:50
     */
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "生成INSERT SQL", notes = "传入tableName")
    @ApiLog("生成INSERT SQL")
    @Log(title = "生成INSERT SQL", businessType = BusinessType.OTHER)
    @PostMapping("/downloadFileZip")
    public void downloadFileZip(@RequestParam("FileName") String FileName, HttpServletResponse httpServletResponse) {
        FileName = StringUtils.downLoadReplace(FileName);
        if (FileUtils.downloadFile(FileName, httpServletResponse)) {
            FileUtils.deleteFile(FileName);
        }
    }

    /**
     * @param productIds      产品id
     * @param searchValue     搜索条件
     * @param downloadType    0-系统  1-产品
     * @param downloadNumType 0-所有  1-非门户
     * @return String
     * @throws ParseException
     * @Description 导出系统、产品及下属关系层级
     * @Author lizeyu
     * @Date 2021年4月22日 14:30:50
     */
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "生成INSERT SQL", notes = "传入tableName")
    @ApiLog("生成INSERT SQL")
    @Log(title = "生成INSERT SQL", businessType = BusinessType.OTHER)
    @PostMapping("/createTableInsertByProductEnameList")
    public R createTableInsertByProductEnameList(
            @ApiParam(value = "基础产品id", required = true) @RequestParam("productIds") String productIds,
            @ApiParam(value = "系统id", required = true) @RequestParam("sysIds") String sysIds,
            @ApiParam(value = "接口id", required = true) @RequestParam("apiIds") String apiIds,
            @RequestParam("searchValue") String searchValue,
            @RequestParam("downloadType") String downloadType,
            @RequestParam("downloadNumType") String downloadNumType,
            @RequestParam("exportFile") String exportFile) {

        switch (downloadType) {
            case "0":
                return expSeqService.createTableInsertBySysIds(sysIds, searchValue, downloadNumType, exportFile);
            case "1":
                return expSeqService.createTableInsertByProductIds(productIds, searchValue, downloadNumType, exportFile);
            case "2":
                return expSeqService.createTableInsertByApiIds(apiIds, searchValue, downloadNumType, exportFile);
            case "3":
                break;
            default:
                log.error("生成INSERT SQL失败：{}");
                return R.fail("生成INSERT SQL失败");
        }

        return R.data(null);

    }


    /*
     * @Description 修改导出标识
     * @Author xiafayu
     * @Date 2020/12/24 15:01
     * @param  tableName  表名
     * @return String
     * @throws  ParseException
     **/
    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "修改导出标识", notes = "")
    @ApiLog("修改导出标识")
    @Log(title = "修改导出标识", businessType = BusinessType.OTHER)
    @PostMapping("/updateExpSeq")
    public R updateExpSeq(@RequestBody ExpSeq exp) {
        String expSeq = exp.getExpSeq();
        String expSeqStr = serialNumberService.generateSerialNumberByModelCode("exp_seq");
        if (expSeq == null) {
            exp.setExpSeq(expSeqStr);
        }
        stringRedisTemplate.opsForValue().set(EXP_SQE, exp.getExpSeq());
        BladeUser user = AuthUtil.getUser();
        if (user != null) {
            exp.setCreateUser(user.getUserId());
            exp.setCreateDept((Long) Func.toLongList(user.getDeptId()).iterator().next());
            exp.setUpdateUser(user.getUserId());
        }

        Date now = DateUtil.now();
        exp.setCreateTime(now);
        exp.setUpdateTime(now);
        exp.setStatus(1);
        exp.setIsDeleted(0);
        expSeqService.saveOrUpdate(exp);
        return R.success("修改导出标识成功");
    }

    /*
     * @Description 查询导出标识版本
     * @Author xiafayu
     * @Date 2020/12/24 15:01
     * @throws  ParseException
     **/
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "查询导出标识版本", notes = "")
    @ApiLog("查询导出标识版本")
    @Log(title = "查询导出标识版本", businessType = BusinessType.OTHER)
    @GetMapping("/queryExpSeq")
    public R queryExpSeq() {
        String str = stringRedisTemplate.opsForValue().get(EXP_SQE);
        if (str == null) {
            List<String> expSeqList = jdbcTemplate.queryForList(DATA_BY_EXP_SEQ, String.class);
            str = expSeqList.get(0);
        }
        Integer expSeq = Integer.valueOf(str) + 1;
        return R.data(frontCompWithZore(4, expSeq));
    }

    @GetMapping("getExpSeqList")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "查询导出标识", notes = "")
    @ApiLog("查询导出标识")
    @Log(title = "查询导出标识", businessType = BusinessType.OTHER)
    public R getExpSeqList(Query query, String expSeq) {
        IPage<ExpSeq> list = expSeqService.queryExpSeq(Condition.getPage(query), expSeq);
        return R.data(list);
    }

    @PostMapping("importFile")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "导入数据", notes = "")
    @ApiLog("导入数据")
    @Log(title = "导入数据", businessType = BusinessType.OTHER)
    @Transactional(rollbackFor = Exception.class)
    public R importFile(HttpServletRequest request) {
        try {
            String sql = FilEUploadUtils.convertStreamToString(request);
            if (sql.length() < 1) {
                return R.fail("导入文件内容不能为空！");
            }
            String[] sqlStr = sql.split(";");
            int[] res = jdbcTemplate.batchUpdate(sqlStr);
            log.info("插入成功：[{}]条数据", res.length);
        } catch (Exception e) {
            log.error("导入数据失败：{}", e);
            if (e.getMessage().contains("ORA-00001: 违反唯一约束条件")) {
                return R.fail(222, "导入数据已存在，请重新核对导入文件数据！");
            }
            if (e.getMessage().contains("for key 'PRIMARY'")) {
                return R.fail(222, "导入数据已存在，请重新核对导入文件数据！");
            }
            return R.fail(222, "导入数据失败");
        }
        return R.success("导入成功");
    }

    /**
     * 将元数据前补零，补后的总长度为指定的长度，以字符串的形式返回 @param sourceDate @param             formatLength @return
     * 重组后的数据
     */
    public static String frontCompWithZore(Integer formatLength, Integer formatNumber) {
        /**
         * 0 指前面补充零
         * formatLength 字符总长度为 formatLength
         * inputNumber 格式化数字
         * d 代表为正数。
         */
        String newString = String.format("%0" + formatLength + "d", formatNumber);
        return newString;
    }

}
